package com.ketti.team;

import java.util.ArrayList;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;

public class NewEditText extends EditText {	
	
	// these varibles for draw background
	private Paint marginPaint;
	private Paint linePaint;
	private Paint textPaint;
	private Paint lineHighLightPaint;
	
	private int paperColor;
	
	private int selectedLineNumber = 0;	
	
	private float margin;
	
	private boolean layoutState = false;
	
	private ArrayList<String> lineIndex = new ArrayList<String>();	
	
	// these varibles for controlling searchBox
	private LinearLayout 	searchBoxLayout;
	private EditText 		searchBoxEdit;	
	
	// This is keyword to highlight
	private final String[] keyWordList = new String[] {
			"abstract", "assert", "boolean", "break", "byte", 
			"case", "catch", "char", "class", "const",
			"continue", "default", "do", "double", "else", 
			"enum", "extends", "false", "final", "finally",
			"float", "for", "goto", "if", "implements",
            "import", "instanceof", "int", "interface", "long", 
            "native", "new", "null", "package", "private", "protected",
            "public", "return", "short", "static", "strictfp",
            "super", "switch", "synchronized", "this", "throw", "throws",
            "true", "transient", "try", "void", "volatile", "while"
            };
	
	private final String[] CommentList = new String[] {"//", "/*", "*/"};//, "/", "*"};
	
	private InputFilter keyWordInputFilter, CommentInputFilter;	
	
	public NewEditText(Context context) {
		super(context);
		init();
		// TODO Auto-generated constructor stub
	}
	
	public NewEditText(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
		// TODO Auto-generated constructor stub
	}	
	
	public NewEditText(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
		// TODO Auto-generated constructor stub
	}

	public void setSearchBoxLayout(LinearLayout layout){
		searchBoxLayout = layout;
	}
	
	public void setSearchBoxEdit(EditText editText){
		searchBoxEdit = editText;
	}					
	
	/* remove current line's highlights for keyword and comment */	
	public void removeSelectedLineHighlight(){		
		Editable source = getText();		
		int start = getLayout().getLineStart(selectedLineNumber);
		int end = getLayout().getLineEnd(selectedLineNumber);
		source.setSpan(new ForegroundColorSpan(Color.BLACK), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	}
	
	/* return start of current line */
	public int getCurrentLineStart(){
		if(selectedLineNumber !=0 )
			return getLayout().getLineStart(selectedLineNumber);
		else
			return 0;
	}
	
	/* return start of specified line */
	public int getCurrentLineStart(int lineNumber){
		if(lineNumber !=0 )
			return getLayout().getLineStart(lineNumber);
		else
			return 0;
	}
	
	/* return end of current line */
	public int getCurrentLineEnd(){
		return getLayout().getLineEnd(selectedLineNumber);
	}
	
	/* return end of specified line */
	public int getCurrentLineEnd(int lineNumber){
		return getLayout().getLineEnd(lineNumber);
	}	

	@Override
	public boolean onTouchEvent(MotionEvent event) {		
		
		// if this view is touched with more than 1 finger, toggle search box 
		if(event.getPointerCount() > 1){				
			if(event.getAction() == MotionEvent.ACTION_POINTER_UP){					
				if(layoutState == false){					
					searchBoxLayout.setVisibility(View.VISIBLE);
					searchBoxEdit.requestFocus();					
					layoutState = true;					
				}
				else{
					if((event.getAction() == MotionEvent.ACTION_MOVE) || (event.getAction() == MotionEvent.ACTION_POINTER_UP))
						searchBoxLayout.setVisibility(View.GONE);
						layoutState = false;
				}
			}		
		}
		else{
			super.onTouchEvent(event);					
		}
		return true;
	}
	
	/* initialize paints for draw and filters*/
	private void init() {
		Resources myResources = getResources();
		
		marginPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		marginPaint.setColor(myResources.getColor(R.color.notepad_margin));
		marginPaint.setStrokeWidth(0);
		
		linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		linePaint.setColor(myResources.getColor(R.color.notepad_lines));
		linePaint.setStrokeWidth(0);
		
		textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		textPaint.setColor(myResources.getColor(R.color.notepad_text));
		textPaint.setTextAlign(Align.RIGHT);
		
		lineHighLightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		lineHighLightPaint.setColor(myResources.getColor(R.color.line_highlight));
		
		paperColor = myResources.getColor(R.color.notepad_paper);
		margin = myResources.getDimension(R.dimen.notepad_margin);
							
		setKeyWordInputFilter();
		setCommentInputFilter();
		setFilters(new InputFilter[] {keyWordInputFilter, CommentInputFilter}); 
		getLineIndex();
	}
	
	@Override
	protected void onDraw(Canvas canvas) {	
		
		int lineCount = this.getLayout().getLineCount();						
		
		canvas.drawColor(paperColor);				
		canvas.drawLine(margin-5, 0, margin-5, getMeasuredHeight(), marginPaint);
		canvas.drawLine(margin, 0, margin, getMeasuredHeight(), marginPaint);
		
		// draw rectangle to highlight line
		canvas.drawRect(margin, this.getLayout().getLineBottom(selectedLineNumber) + this.getLayout().getLineAscent(selectedLineNumber), getMeasuredWidth(), this.getLayout().getLineBottom(selectedLineNumber) + this.getLayout().getLineDescent(selectedLineNumber), lineHighLightPaint);
		
		// draw lines and line number
		for(int i = 0 ; i < lineCount ; i++){
			canvas.drawLine(0, this.getLayout().getLineBottom(i) + this.getLayout().getLineDescent(i), getMeasuredWidth(), this.getLayout().getLineBottom(i) + this.getLayout().getLineDescent(i),linePaint);
			canvas.drawText(Integer.toString(i+1), 20, this.getLayout().getLineBottom(i), textPaint);			
		}		
				
		canvas.save();		
		canvas.translate(margin, 0);		
		super.onDraw(canvas);			
		canvas.restore();			
	}
	
	/* update selectedLineNumber by current cursor's location */
	public void getCurrentLineByCursor(int cursor){
		for(String s : lineIndex){									
			if(cursor < Integer.valueOf(s)){	
				selectedLineNumber = lineIndex.indexOf(s);						
				break;						
			}	
			
			// when the cursor is in the last line
			else if(cursor >= Integer.valueOf(lineIndex.get(lineIndex.size()-1))){
				selectedLineNumber = lineIndex.size();
				break;
			}
		}
	}

	/* invoked when user change cursor */
	@Override
	protected void onSelectionChanged(int selStart, int selEnd) {		
		int previousLineNumber = selectedLineNumber;
		if(this.getText() != null && getLayout() != null){
			getCurrentLineByCursor(selStart);					
		}							
		refreshLineHighlight(previousLineNumber);			
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {		
		int previousLineNumber = selectedLineNumber;				
		
		switch(event.getKeyCode()){
		
			// when 'enter' key down, always increase line number (selectedLineNumber)
			case KeyEvent.KEYCODE_ENTER :
				selectedLineNumber++;										
				refreshLineHighlight(previousLineNumber);				
				return super.onKeyDown(keyCode, event);
			
			// when 'del' key down, remove current line's keyword and comment span and call 'setKeywordForLine'
			// 'setCommentForLine' methods to check 
			case KeyEvent.KEYCODE_DEL:					
				getCurrentLineByCursor(getSelectionStart()-1);			
				removeSelectedLineHighlight();				
				setKeywordForLine(selectedLineNumber);
				setCommentForLine(selectedLineNumber);
				refreshLineHighlight(previousLineNumber);				
				return super.onKeyDown(keyCode, event);
				
			default:				
				return super.onKeyDown(keyCode, event);
		}						
	}
	
	/**
	 * if the line number changed, redraw previous and current line highlight 
	 * and check line index again. 
	 **/
	private void refreshLineHighlight(int previousLineNumber){
		if(previousLineNumber != selectedLineNumber){
			getLineIndex();
			invalidate((int)margin, this.getLayout().getLineBottom(selectedLineNumber) + this.getLayout().getLineAscent(selectedLineNumber), getMeasuredWidth(), this.getLayout().getLineBottom(selectedLineNumber) + this.getLayout().getLineDescent(selectedLineNumber));
			invalidate((int)margin, this.getLayout().getLineBottom(previousLineNumber) + this.getLayout().getLineAscent(previousLineNumber), getMeasuredWidth(), this.getLayout().getLineBottom(selectedLineNumber) + this.getLayout().getLineDescent(previousLineNumber));
		}
	}
	
	/* get line index from source string  and save it to lineIndex array list */
	private void getLineIndex(){		
		int line_index = 0;
		
		String source = getText().toString();
		
		lineIndex.clear();
		
		if(source != null){
			for(int i = 0 ; i < source.length() ; i++){
				if(source.charAt(i)=='\n')
					lineIndex.add(line_index ++, Integer.toString(i+1));
         }
			// add last line index manually
			lineIndex.add(line_index ++, Integer.toString(source.length()));
		}		
	}	
	
	/**
	 * Setup keyword filter to highlight keyword in source. if user put 
	 * some keyword to EditText, this filter automatically change this word to red 
	 **/	
	 private void setKeyWordInputFilter() {
	    	keyWordInputFilter = new InputFilter() {
				
				@Override
				public CharSequence filter(CharSequence source, int start, int end,
						Spanned dest, int dstart, int dend) {
					for(String s : keyWordList)
					{						
						if(s.equals(source))
						{													
							SpannableString sp = new SpannableString(source);
							sp.setSpan(new ForegroundColorSpan(Color.RED), 0, s.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);							
							return sp;
						}						
					}
					return source;
				}
			};
	}
	 
	/**
	 * Setup Comment filter to highlight comment in source. if user put 
	 * some comment to EditText, this filter automatically change this word to green
	 **/
	 private void setCommentInputFilter(){
		 CommentInputFilter = new InputFilter() {
			
			@Override
			public CharSequence filter(CharSequence source, int start, int end,
					Spanned dest, int dstart, int dend) {				
				for(String s : CommentList)
				{
					if(s.equals(source))
					{												
						SpannableString sp = new SpannableString(source);
						sp.setSpan(new ForegroundColorSpan(Color.GREEN), 0, s.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
						return sp;
					}
				}
				return source;
			}
		};
	 }	 
	 
	 /**
	  * find keyword and comment in initial source and change them to red, green.
	  * this method called once, when source view initialize its text.
	  * after initialized, use "refreshEntireText" method to change entire source. 		
	  **/	 
	public void setInitialKeyWordFilter() {
		
		Editable source = getText();        		
		
        for(String s : keyWordList){ 
        	int currentIndexEnd = 0;
        	int currentIndex = 0;
        	while(source.toString().indexOf(s, currentIndexEnd) != -1){
	        	if(currentIndexEnd == 0)
	        		currentIndex = source.toString().indexOf(s);	        			        	
	        	else
	        		currentIndex = source.toString().indexOf(s, currentIndexEnd);	 
	        	
	        	currentIndexEnd = currentIndex + s.length();
        		source.setSpan(new ForegroundColorSpan(Color.RED), currentIndex, currentIndexEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        	}
        } 
        
        for(String s : CommentList){
        	int currentIndexEnd = 0;
        	int currentIndex = 0;
        	while(source.toString().indexOf(s, currentIndexEnd) != -1){
	        	if(currentIndexEnd == 0){
	        		currentIndex = source.toString().indexOf(s);
	        		currentIndexEnd = currentIndex + s.length();	
	        		if(s.equals("//"))
	        			source.setSpan(new ForegroundColorSpan(Color.GREEN), currentIndex, source.toString().indexOf("\n", currentIndexEnd), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	        		else
	        			source.setSpan(new ForegroundColorSpan(Color.GREEN), currentIndex, currentIndexEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	        	}
	        	else{
	        		currentIndex = source.toString().indexOf(s, currentIndexEnd);
	        		currentIndexEnd = currentIndex + s.length();
	        		source.setSpan(new ForegroundColorSpan(Color.GREEN), currentIndex, currentIndexEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	        	}
        	}
        }
	}
	
	/**
	 * check all source in this and find keyword, comment	   	
	 **/	
	public void refreshEntireText() {		
		getLineIndex();				
		
		int lineCount = getLayout().getLineCount();
		for(int i = 0 ; i < lineCount ; i ++){
			setKeywordForLine(i);
			setCommentForLine(i);

		}
	}
	
	/**
	 * find keyword and change its color to red in specified line	   	
	 **/
	public void setKeywordForLine(int lineNumber){		
		Editable source = getText();				
		
		int indexStart = getCurrentLineStart(lineNumber);
		int indexEnd = getCurrentLineEnd(lineNumber);
		
		String subSource = source.toString().substring(indexStart, indexEnd); 

		for(String s : keyWordList){ 
        	int currentIndexEnd = 0;
        	int currentIndex = 0;
        	while(subSource.indexOf(s, currentIndexEnd) != -1){
	        	if(currentIndexEnd == 0)
	        		currentIndex = subSource.indexOf(s);	        			        	
	        	else
	        		currentIndex = subSource.indexOf(s, currentIndexEnd);	 
	        	
	        	currentIndexEnd = currentIndex + s.length();
        		source.setSpan(new ForegroundColorSpan(Color.RED), currentIndex + indexStart, currentIndexEnd + indexStart, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        	}
        } 		
		
	}
	
	/**
	 * find comment and change its color to green in specified line	   	
	 **/
	public void setCommentForLine(int lineNumber){
		
		Editable source = getText();				
		
		int indexStart = getCurrentLineStart(lineNumber);
		int indexEnd = getCurrentLineEnd(lineNumber);
		
		String subSource = source.toString().substring(indexStart, indexEnd); 
		
		for(String s : CommentList){
        	int currentIndexEnd = 0;
        	int currentIndex = 0;
        	while(subSource.indexOf(s, currentIndexEnd) != -1){
	        	if(currentIndexEnd == 0){
	        		currentIndex = subSource.indexOf(s);
	        		currentIndexEnd = currentIndex + s.length();	
	        		if(s.equals("//"))
	        			source.setSpan(new ForegroundColorSpan(Color.GREEN), currentIndex + indexStart, indexEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	        		else
	        			source.setSpan(new ForegroundColorSpan(Color.GREEN), currentIndex + indexStart, currentIndexEnd + indexStart, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	        	}
	        	else{
	        		currentIndex = source.toString().indexOf(s, currentIndexEnd);
	        		currentIndexEnd = currentIndex + s.length();
	        		source.setSpan(new ForegroundColorSpan(Color.GREEN), currentIndex + indexStart, currentIndexEnd + indexStart, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
	        	}
        	}
        }
	}
}
